home *** CD-ROM | disk | FTP | other *** search
- Path: goanna.cs.rmit.EDU.AU!not-for-mail
- From: ok@goanna.cs.rmit.EDU.AU (Richard A. O'Keefe)
- Newsgroups: comp.lang.ada,comp.lang.c++,comp.lang.c,comp.lang.modula3,comp.lang.modula2
- Subject: Re: Hungarian notation
- Date: 31 Jan 1996 15:57:12 +1100
- Organization: Comp Sci, RMIT, Melbourne, Australia
- Message-ID: <4emsr8$hib@goanna.cs.rmit.EDU.AU>
- References: <30C40F77.53B5@swsbbs.com> <4bd <4cc2b2$11jq@navajo.gate.net> <4cud8f$gup@news.netvision.net.il> <4dttefINNo29@keats.ugrad.cs.ubc.ca> <Pine.HPP.3.91.960122145028.27524A-100000@clear.cs.byu.edu> <dewar.822407363@schonberg> <Pine.HPP.3.91.960124153551.24374C-100000@zeezrom.cs.byu.edu> <4e7ifl$et3@goanna.cs.rmit.EDU.AU> <Pine.HPP.3.91.960129133429.8419C-100000@foggy.cs.byu.edu>
- NNTP-Posting-Host: goanna.cs.rmit.edu.au
- NNTP-Posting-User: ok
- X-Newsreader: NN version 6.5.0 #0 (NOV)
-
- Douglas Evan Cook <cookd@cs.byu.edu> writes:
- >I'm sure I'm missing your point,
- >but it is clear that you are also missing mine.
-
- Perhaps we have a terminology problem.
- Part of the problem is that you keep on talking about 'typedef', which is
- a C concept having nothing to do with abstract data types. All that
- typedef ... identifier ...;
- does in C is to establish identifier as a *synonym* for an existing type
- that can be expressed without it.
-
- Let me briefly describe a language that has abstract data types: Mercury.
- A Mercury module (like an Ada package)
- - can import ABSTRACT types, CONCRETE types, constants, and predicates
- (think 'routines') from other modules
- - can define new types, new constants, and new predicates
- - can export selected predicates and constants, and types with OR WITHOUT
- their representations.
-
- For example, suppose I have a "set(T)" data type implemented by a "set.m"
- module. This module will export
- - the fact that there *exists* a type constructor called set(T)
- - *NO* information at all about the representation of that type
- - a collection of predicates some of which may have parameters of
- type set(X).
- Suppose I also have a "node" data type implemented by a "node.m" module.
- This module will export
- - the fact that there *exists* a type constructor called 'node'
- - *NO* information at all about the representation of that type
- - a collection of predicates some of which may have parameters of
- type 'node'.
- Then I can implement a "graph" data type in a module "graph.h".
- INSIDE the module
- :- type graph = pair(set(node), set(pair(node))).
- I can do this even though *nobody* processing this file has any idea of
- the representation of 'node' or 'set', not the human reader, and not even
- the compiler.
-
- Now this is data abstraction. "graph.m" uses 'node' and 'set(T)' without
- knowing _anything at all_ about those types except their names and the
- names-and-parameter-profiles of the operations on them.
-
- C's "typedef" (and C/ObjC/C++ are the only languages I know having a
- "typedef" keyword) is by design totally incapable of accomplishing this.
-
-
- About saving and restoring abstract values, I wrote:
- >> As long as there is a Pack.T'Write and a Pack.T'Read (forgive me if
- >> I've got the syntax a bit wrong, I'm still learning about Ada 95
- >> streams) *I* don't have to know what the size of an instance of the
- >> type is in the file. The size appears explicitly nowhere in my code.
-
- to which Douglas Cook replied:
-
- >No, but somebody must have written those methods, no?
-
- Yes, but those methods are INSIDE the abstraction. Of *course* operations
- defined inside an abstraction have access to the representation of the type.
- You appeared to be saying that operations *outside* the abstraction required
- this information, which is simply not true (at least in Mercury).
-
- >And that somebody needed to know how many bits each data type is, no?
-
- No. And "no" in several senses, what's more. First of all, it is not
- the case that any human being ever needed to be aware of what the number
- is. Second, it is not the case that any human being ever needed to be
- in a position where s/he _could_ have computed the number. Third, you
- seem to be assuming that a data type _is_ some definite number of bits,
- which is not necessarily true. (Imagine a Burroughs D-machine implementing
- a language where each variable is accessed via a descriptor; a 'number'
- variable might actually change its size during execution.) Fourth, even
- if (instances of) a data type _are_ some definite number of bits, it is
- not necessarily the case that the compiler know or be able to determine
- this when compiling the inside of the abstraction. (For an example, think
- of C++: if B is a subclass of A, the compiler may be compiling a method
- for A which will actually be called at run time with arguments of class B,
- which hasn't been written yet; the compiler has no idea whatsoever what
- the size of B will be.)
-
- >When we changed from 16 bit compiler to 32 bit compiler,
- >the data files remained the same.
-
- What has that to say to anything? No god ever wrote on a tablet of stone
- that the representation used _inside_ a program had to be the same as the
- representation used _outside_, and it very often isn't true. (For example,
- if you use XDR, a 16-bit little-endian integer in an internal data structure
- will appear in the external data as a 32-bit big-endian integer. A program
- using XDR doesn't know and doesn't have any reason to care.)
-
- >Any code that directly accesses the data structures (which is rare
- >outside of library design) needs to know the data structure.
-
- If you have code that directly accesses a data structure, and that code
- is not *inside* the abstraction, then you haven't got an abstract data type.
-
- >Also, when you are making system calls (in assembler, or when you are
- >interfacing with Windows and need to do an API call) you also need to
- >do bit level interaction with the data structures.
-
- If you *know* what the representation of a data structure is to the bit
- level, then it isn't an abstract data type. Abstraction means HIDING
- all that kind of detail.
-
- For what it's worth, your claim about making system calls may be true in
- some operating systems (it was in TOPS-10, and I have to say that it was
- a major nuisance) but not all of them. For example, in MVS, the assembler
- comes with a library of *macros* for all the system calls and data blocks.
- The macros take care of packing your symbolically provided information into
- the requisite control blocks; I have never known and never had any reason
- to know what the bit level structures actually are. What you are telling
- me is that the MVS interface was abstract and the Windows interface isn't.
-
- I have the three volume "Osborne Windows Programming Series" by Schildt,
- Pappas, and Murray, which lists the Windows API. I have studied these
- volumes from cover to cover, and found no use of ADTs. Typedefs, yes.
- ADTs, no. Let me quote from one randomly selected section (2 facing pages).
-
- BOOL ClipCursor(CONST RECT *lpcRect);
- [Win16: ClipCursor() returns void.]
-
- typedef struct tagRECT {
- LONG left, top, right, bottom;
- } RECT;
- [Win16: the coordinates are of type 'int']
-
- HCURSOR CopyCUrsor(HINSTANCE hInst, HCURSOR hCursor);
- [Win32: the hInst parameter does not exist.]
-
- [pp 504,504 of vol 2; the code example at the top of p505 has bad syntax.]
-
- BOOL, RECT, LONG, HCURSOR, HINSTANCE are not abstract data types.
-
- (Does it make sense that the coordinates of a RECT are LONG in Win32
- and int in Win16, but the coordinates of a POINT are int in both?
- That's what the description of GetCursorPos on p509 claims.)
-
- >How much clearer can I make this? SOMEBODY HAS TO MAKE THE
- >ADT's!
-
- Yes, of course. Nobody has disputed that. But what relevance has it to
- anything else you were saying?
-
- >And when you have thousands of different ADT's in a library, you
- >need some unifying typedefs.
-
- If the abstract types are *different*, what is it that needs to be
- *unified* (made identical)? And how can typedefs (introducing *new names*
- for *existing types*) unify anything, let alone "different ADTs"?
-
- >So TYPEDEFS ARE NOT "USELESS" OR BAD CODING PRACTICE!
- >Sorry for shouting. I just wanted to make sure that you saw these points,
- >because you seem to have missed them in all of my other messages.
-
- I have never argued that typedefs are useless,
- or that they are bad coding practice. Indeed, given C's unusual declaration
- syntax, typedefs are of great value.
-
- But it doesn't matter how much you shout, you cannot change what a typedef
- actually accomplishes:
- - a typedef introduces into the current lexical scope
- - a new identifier that stands for
- - an EXISTING already expressible type.
- This has nothing to do with abstract data types. All it does is let you
- use as many *names* as you want for the same *concrete* type. Yes, you
- can say
- #if defined(Win16) && !defined(Win32)
- typedef int foo;
- #elif defined(Win32) && !defined(Win16)
- typedef long foo;
- #else
- #error "Define exactly one of Win16, Win32"
- #endif
- But you could in any case have written
- #if defined(Win16) && !defined(Win32)
- #define foo int
- #elif defined(Win32) && !defined(Win16)
- #define foo long
- #else
- #error "Define exactly one of Win16, Win32"
- #endif
- It's not the typedef that helps in porting, it's the #if. Neither typedef
- nor #define gives you type abstraction. C++ namespaces and classes do that.
-
- --
- "conventional orthography is ... a near optimal system for the
- lexical representation of English words." Chomsky & Halle, S.P.E.
- Richard A. O'Keefe; http://www.cs.rmit.edu.au/~ok; RMIT Comp.Sci.
-